package com.imu.purse.modules.bitcoin;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.googlecode.jsonrpc4j.JsonRpcHttpClient;
import com.imu.constant.Constant;
import com.imu.purse.bean.CoreMoneyAddr;
import com.imu.purse.bean.YtfInnerTransForm;
import com.imu.purse.bean.YtfTransForm;
import com.xiaoleilu.hutool.log.Log;
import com.xiaoleilu.hutool.log.LogFactory;
import org.ethereum.solidity.Abi;
import org.ethereum.util.ByteUtil;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.ConnectException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

@Component
public class YtfcoinApi {
    private static Log log = LogFactory.get(YtfcoinApi.class);
    /**
     * 初始化client
     */
    private JsonRpcHttpClient initClient(String moneyAddrStr){
        JsonRpcHttpClient client = null;
        try{
            Map<String,String> paramMap = Maps.newHashMap();
            //身份认证
            paramMap.put("Content-Type","application/json");
            CoreMoneyAddr moneyAddr = JSON.parseObject(moneyAddrStr,CoreMoneyAddr.class);
            client = new JsonRpcHttpClient(new URL(moneyAddr.getUrl() + ":" + moneyAddr.getPort()));
            client.setHeaders(paramMap);
        }catch (Exception e){
            log.error(e);
        }
        return client;
    }

    /**
     * 以太坊创建新用户
     * @param phone
     * @param moneyAddrStr
     * @return
     */
    public String createAccount(String phone,String moneyAddrStr){
        try{
            JsonRpcHttpClient client = initClient(moneyAddrStr);
            if(client != null){
                Object result = client.invoke("personal_newAccount", new Object[]{phone},Object.class);
                if(result != null){
                    return result.toString();
                }
            }
        }catch(Throwable e){
            log.error(e);
        }
        return null;
    }

    /**
     *  IMU间转账
     * @param from
     * @param to
     * @param money
     * @param moneyAddrStr
     * @param ytfType
     * @return
     */
    public String sendTransaction(String from,String to,String money,
                                  String password,String moneyAddrStr,int ytfType){
        try{
            //需要将金额转换为16进制
            BigDecimal bigDecimalg = new BigDecimal(money);
            bigDecimalg = bigDecimalg.multiply(new BigDecimal(Constant.MONEY_TO_YTF+""));
            String moneyStr = Long.toHexString(bigDecimalg.longValue());//10进制转换为16进制
            Object obj = null;
            //A1->B1 From:A to:IMU合约地址 ,Data: A1+money加密
            //A-->A1 原生币 From:A to:A1
            //A1-->A 代币 From:A1,to:IMU合约地址,Data:A+money加密
            if(ytfType == 0){//A1->B1  A1-->A
                //将小钱包地址和金额进行加密
                byte[] bytes = Abi.fromJson(Constant.IMU_ABI).findFunction(function -> "transfer".equals(function.name))
                        .encode(to.substring(2),moneyStr);
                String input = ByteUtil.toHexString(bytes);
                input = input.startsWith(Constant.YTF_PERFIX) ? input : Constant.YTF_PERFIX + input;
                //构建传输的参数  接口调用参数需要确认
                YtfTransForm form = new YtfTransForm();
                form.setFrom(from);
                form.setTo(Constant.IMU_CONTRACT_ADDRESS);
                form.setValue(Constant.YTF_16_0);
                form.setData(input);
                obj = JSON.toJSON(form);
            }else {//A-->A1
                YtfInnerTransForm form = new YtfInnerTransForm();
                form.setFrom(from);
                form.setTo(to);
                form.setValue("0x" + moneyStr);
                obj = JSON.toJSON(form);
            }
            /*YtfInnerTransForm form = new YtfInnerTransForm();
            form.setFrom(from);
            form.setTo(to);
            form.setValue("0x" + moneyStr);
            obj = JSON.toJSON(form);*/
            JsonRpcHttpClient client = initClient(moneyAddrStr);
            if(client != null){
                Object result = client.invoke("personal_signAndSendTransaction",
                        new Object[]{obj,password},Object.class);
                if(result != null){
                    return result.toString();
                }
            }
        }catch(Throwable e){
            log.error(e);
        }
        return null;
    }


    /**
     * 获取当前区域的高度
     * @param moneyAddrStr
     * @return
     */
    public Integer getblockcount(String moneyAddrStr){
        try{
            JsonRpcHttpClient client = initClient(moneyAddrStr);
            if(client != null){
                Object result = client.invoke("eth_blockNumber", new Object[]{},Object.class);
                if(result != null){
                    return Integer.valueOf(result.toString().substring(2),16);
                }
            }
        }catch(Throwable e){
            log.error(e);
        }
        return null;
    }

    /**
     * 根据高度获取块的信息
     * @param height
     * @param moneyAddrStr
     * @return
     */
    public Map<String,Object> getBlock(Integer height,String moneyAddrStr){
        try{
            JsonRpcHttpClient client = initClient(moneyAddrStr);
            if(client != null){
                Object result = client.invoke("eth_getBlockByNumber", new Object[]{Constant.YTF_PERFIX + Long.toHexString(height),true},Object.class);
                if(result != null){
                    return (Map<String,Object>)result;
                }
            }
        }catch(Throwable e){
            return initError(e);
        }
        return null;
    }

    /**
     * @param tranId
     * @param moneyAddressStr
     * @return
     */
    public Map<String,Object> getTranscationInfo(String tranId,String moneyAddressStr){
        try{
            JsonRpcHttpClient client = initClient(moneyAddressStr);
            Object result = client.invoke("gettransaction", new Object[]{tranId},Object.class);
            if(result != null){
                return (Map<String,Object>)result;
            }
        }catch(Throwable e){
            return initError(e);
        }
        return null;
    }

    /**
     * 处理错误
     * @param e
     * @return
     */
    private Map<String,Object> initError(Throwable e){
        Map<String,Object> rMap = new HashMap<>(1);
        rMap.put("error", Constant.MONEY_PACKAGE_CONNECT_OTHER_ERROR);
        if(e instanceof ConnectException){//如果是连接异常代表钱包程序出问题聊
            rMap.put("error", Constant.MONEY_PACKAGE_CONNECT_ERROR);
        }
        return rMap;
    }

    public static void main(String[] args){
        BigDecimal bigDecimal = new BigDecimal("0.002");
        bigDecimal = bigDecimal.multiply(new BigDecimal(Constant.MONEY_TO_YTF+""));

        BigInteger bigInteger = new BigInteger(bigDecimal.longValue()+"",16);
        System.out.println(bigInteger);

        String abi = "[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_spender\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"balance\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_spender\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"},{\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"approveAndCall\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"remaining\",\"type\":\"uint256\"}],\"type\":\"function\"},{\"inputs\":[{\"name\":\"_initialAmount\",\"type\":\"uint256\"},{\"name\":\"_tokenName\",\"type\":\"string\"},{\"name\":\"_decimalUnits\",\"type\":\"uint8\"},{\"name\":\"_tokenSymbol\",\"type\":\"string\"}],\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"}]";
        String input = "0xa9059cbb000000000000000000000000f31f3b73271daf9c7e8a229a8a89d2af3506ba2600000000000000000000000000000000000000000000d3c18326f3356fb40000";

        byte [] b = Abi.fromJson(abi).findFunction(function -> "transfer".equals(function.name))
                .encode("7c6eff8b4c3ed60b40a0eee63af55ffc759e4357","536870912");

        String encodeStr = "0x" + ByteUtil.toHexString(b);
        System.out.println(encodeStr);

        BigDecimal money = new BigDecimal("20000000");
        System.out.println(money.divide(new BigDecimal(Math.pow(10,10))));

        Integer integer = 800;
        System.out.println(Integer.toHexString(800));
    }
}
